package network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//ServerSocket 相当于银行大厅的接待员 Socket相当于银行柜台里面的服务员
public class TcpEchoServer {
    private ServerSocket serverSocket=null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器已启动");
        //一般不使用固定线程池 fiexdThreadPool 客户端数量就固定了
        ExecutorService executorService= Executors.newCachedThreadPool();
        while(true){
            //建立与客户端连接
            //通过clientSocket与客户端进行通信
            //如果没有客户端发起连接 accept会阻塞等待
            //主线程要一直循环等待客户端连接
            //主线程负责accept 每次accept一个客户端 创建一个新线程处理客户端请求
           Socket clientSocket=serverSocket.accept();
           //方法一:使用多线程的方式来调整 当客户端数量太大 客户端线程创建与销毁太频繁 消耗资源大
/*           Thread t=new Thread(()->{
               processConnection(clientSocket);
           });
           t.start();*/
            //方法二:使用线程池的方式来调整
            executorService.submit(()->{
                processConnection(clientSocket);
            });
        }
    }
    //处理一个客户端的连接并处理多个请求和响应
    private void processConnection(Socket clientSocket){
        System.out.printf("[%s:%d] 客户端上线！\n",clientSocket.getInetAddress(),clientSocket.getPort());
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()){
            Scanner scanner=new Scanner(inputStream);
            PrintWriter writer=new PrintWriter(outputStream);
            while(true){
                //1.读取请求并解析 可以直接read 也可以用Scanner辅助完成 用Scanner更方便
                if(!scanner.hasNext()){
                    System.out.printf("[%s:%d] 客户端下线！\n",clientSocket.getInetAddress(),clientSocket.getPort());
                    break;
                }
                String request=scanner.next();
                //2.根据请求 计算响应
                String response=process(request);
                //3.返回给客户端
                writer.println(response);//约定请求响应 用\n做为结束标记
                writer.flush();
                //打印日志
                System.out.printf("[%s:%d] req:%s,resp:%s\n",clientSocket.getInetAddress(),clientSocket.getPort()
                        ,request, response);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                clientSocket.close();//每个客户端结束都需要关闭 防止泄露资源 占用文件描述表
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer server=new TcpEchoServer(9090);
        server.start();
    }
}
